#!/usr/bin/python3
# -*- coding: utf-8 -*-

import os
import logging
import json
import aiohttp_jinja2
from aiohttp import web

import db
from utils import Scriptutils, Blogutils, Hlsutils
from coreweb import query_string, post_params


class Controller(object):
    def __init__(self, prefix, template, table, utils, update_fields):
        self._prefix = prefix
        self._template = template
        self._table = table
        self._utils = utils
        self._post = set(['save', 'itemimport', 'move',
                          'delete', 'mkdir', 'status'])
        self._get = set(['items', 'edit', 'view',
                         'getitem', 'export'])
        self._update_fields = update_fields

    def __repr__(self):
        return "<%s{prefix: %s, template: %s, table: %s, utils: %s}>" % (self.__class__.__name__, self._prefix, self._template, self._table, self._utils)

    def getPost(self):
        return self._post

    def getGet(self):
        return self._get

    async def items(self, request):
        params = query_string(request)
        path = params.get('path', '/root')
        mode = params.get('mode', 'list')
        data = self._utils.getitems(path)
        data = dict(data, **request.app['view_commons'])
        # list-列表模式,view-视图模式
        data['mode'] = mode if mode in ['list', 'view'] else 'list'
        data['prefix'] = self._prefix
        return {'data': data, '__template__': self._template}

    async def edit(self, request):
        params = query_string(request)
        id = params.get('id', None)
        path = params.get('path', '/root')
        item = None
        result = self._utils.get_item(path)
        if result['status']:
            item = result['msg']
        else:
            logging.error('[ERROR]get item: %s' % result['msg'])
        if item is None:
            item = self._table()
        data = {}
        data = dict(data, **request.app['view_commons'])
        data['item'] = item
        data['mode'] = 'edit'
        data['prefix'] = self._prefix
        data['path'] = path[1:].split('/')
        return {'data': data, '__template__': self._template}

    async def save(self, request):
        try:
            params = await request.json()
            data = {}
            for item in self._update_fields:
                value = params.get(item, None)
                if value is None or len(value) <= 0:
                    return {'code': -1, 'msg': '%s in [%s]: %s' % (item, params, value)}
                data[item] = value
            result = self._utils.save_item(dict(params, **data), None)
            if result['status']:
                return {'code': 0, 'msg': result['msg']}
            logging.error('failed to save[%s]: %s' %
                          (params.get('path', 'path'), result))
            return {'code': -1, 'msg': 'failed to save[%s]: %s' % (params.get('path', 'path'), result)}
        except BaseException as e:
            logging.error('failed to save: %s' % e)
            return {'code': -1, 'msg': 'failed to save: %s' % e}

    async def view(self, request):
        params = query_string(request)
        path = params.get('path', '/root')
        item = None
        result = self._utils.get_item(path)
        if result['status']:
            item = result['msg']
        else:
            logging.error('[ERROR]get item: %s' % result['msg'])
        if item is None:
            item = self._table()
        data = {}
        data = dict(data, **request.app['view_commons'])
        data['item'] = item
        data['mode'] = 'detail'
        data['prefix'] = self._prefix
        data['path'] = path[1:].split('/')
        return {'data': data, '__template__': self._template}

    async def mkdir(self, request):
        try:
            params = await request.json()
            parent = params['parent']
            name = params['name']
            result = self._utils.makedir(parent, name)
            if result['status']:
                return web.json_response({'code': 0, 'msg': parent})
            logging.error('failed to makedir(%s, %s): %s' %
                          (parent, name, result['msg']))
            return web.json_response({'code': -1, 'msg': 'failed to makedir(%s, %s): %s' % (parent, name, result['msg'])})
        except BaseException as e:
            logging.error('failed to mkdir: %s' % e)
            return {'code': -1, 'msg': 'failed to mkdir: %s' % e}

    async def delete(self, request):
        try:
            params = await request.json()
            print(params)
            paths = json.loads(params.get('paths', '[]'), encoding='utf-8')
            result = self._utils.delete(paths)
            if result['status']:
                return web.json_response({'code': 0, 'msg': result['msg']})
            logging.error('failed to delete(%s): %s' % (paths, result['msg']))
            return web.json_response({'code': -1, 'msg': 'failed to delete(%s): %s' % (paths, result['msg'])})
        except BaseException as e:
            logging.error('failed to delete: %s' % e)
            return {'code': -1, 'msg': 'failed to delete: %s' % e}

    async def getitem(self, request):
        try:
            params = query_string(request)
            fullpath = params['fullpath']
            result = self._utils.get_item(fullpath)
            if result['status']:
                return {'code': 0, 'msg': result['msg']}
            logging.error('failed to get item[%s]: %s' % (
                fullpath, result['msg']))
            return {'code': -1, 'msg': 'failed to get item[%s]: %s' % (fullpath, result['msg'])}
        except BaseException as e:
            logging.error('failed to getitem: %s' % e)
            return {'code': -1, 'msg': 'failed to getitem: %s' % e}

    async def status(self, request):
        try:
            params = await request.json()
            fullpath = params['fullpath']
            status = params['status']
            result = self._utils.set_item_status(fullpath, status)
            if result['status']:
                return {'code': 0, 'msg': result['msg']}
            logging.error('failed to set [%s] status[%s]: %s' %
                          (fullpath, status, result['msg']))
            return {'code': -1, 'msg': 'failed to set [%s] status[%s]: %s' % (fullpath, status, result['msg'])}
        except BaseException as e:
            logging.error('failed to set status: %s' % e)
            return {'code': -1, 'msg': 'failed to set status: %s' % e}

    async def move(self, request):
        try:
            params = await request.json()
            paths = json.loads(params.get('paths', '[]'), encoding='utf-8')
            newpath = params['newpath']
            result = self._utils.move(paths, newpath)
            if result['status']:
                return {'code': 0, 'msg': result['msg']}
            logging.error('failed to move [%s] to [%s]: %s' %
                          (paths, newpath, result['msg']))
            return {'code': -1, 'msg': 'failed to move [%s] to [%s]: %s' % (paths, newpath, result['msg'])}
        except BaseException as e:
            logging.error('failed to move: %s' % e)
            return {'code': -1, 'msg': 'failed to move: %s' % e}

    async def export(self, request):
        try:
            params = query_string(request)
            paths = json.loads(params.get('paths', '[]'), encoding='utf-8')
            result = self._utils.item_export(paths)
            if result['status']:
                return {'code': 0, 'msg': json.dumps(result['msg'], ensure_ascii=False)}
            logging.error('failed to export [%s]: %s' % (paths, result['msg']))
            return {'code': -1, 'msg': 'failed to export [%s]: %s' % (paths, result['msg'])}
        except BaseException as e:
            logging.error('failed to export: %s' % e)
            return {'code': -1, 'msg': 'failed to export: %s' % e}

    async def itemimport(self, request):
        try:
            params = await request.json()
            data = params['data']
            if len(data) <= 0:
                logging.error('failed to import data: %s' % (data))
                return {'code': -1, 'msg': 'failed to import data %s' % (data)}
            data = data.replace('"None"', 'null')
            result = self._utils.item_import(
                json.loads(data, encoding='utf-8'))
            if result['status']:
                return {'code': 0, 'msg': result['msg']}
            logging.error('failed to import [%s]: %s' % (data, result['msg']))
            return {'code': -1, 'msg': 'failed to import [%s]: %s' % (data, result['msg'])}
        except BaseException as e:
            logging.error('failed to import: %s' % e)
            return {'code': -1, 'msg': 'failed to import: %s' % e}


class BlogView(Controller):
    def __init__(self, prefix='/blog', template='blog.html', table=db.Blog, utils=Blogutils()):
        Controller.__init__(self, prefix, template, table, utils, update_fields=[
                            'name', 'summary', 'content', 'path'])


class ScriptView(Controller):
    def __init__(self, prefix='/script', template='script.html', table=db.Script, utils=Scriptutils()):
        Controller.__init__(self, prefix, template, table,
                            utils, update_fields=['name', 'content', 'path'])
        self._post.add('run')

    async def run(self, request):
        params = await request.json()
        content = params.get('content', None)
        if content is None or len(content) <= 0:
            return {'code': -1, 'msg': 'content [%s]: %s' % (params, content)}
        result = await self._utils.exec(content)
        if result['status']:
            return {'code': 0, 'msg': result['msg']}
        logging.error('failed to exec[%s]: %s' % (content, result))
        return {'code': -1, 'msg': 'failed to exec[%s]: %s' % (content, result['msg'])}


class HlsView(Controller):
    def __init__(self, prefix='/hls_', template='hls_.html', table=db.Hlsitem, utils=Hlsutils()):
        Controller.__init__(self, prefix, template, table,
                            utils, update_fields=['status', 'path'])
        self._post.add('hls_start')
        self._post.add('hls_pause')
        self._post.add('update_poster')
        self._get.add('hls_status')

    async def hls_start(self, request):
        try:
            params = await request.json()
            paths = json.loads(params.get('paths', '[]'), encoding='utf-8')
            result = await self._utils.start(paths)
            if result['status']:
                return {'code': 0, 'msg': result['msg']}
            logging.error('failed to start with %s: %s' % (paths, result))
            return {'code': -1, 'msg': 'failed to start with %s: %s' % (paths, result['msg'])}
        except BaseException as e:
            logging.error('failed to start: %s' % e)
            return {'code': -1, 'msg': 'failed to start: %s' % e}

    async def hls_pause(self, request):
        try:
            params = await request.json()
            paths = json.loads(params.get('paths', '[]'), encoding='utf-8')
            result = await self._utils.pause(paths)
            if result['status']:
                return {'code': 0, 'msg': result['msg']}
            logging.error('failed to pause with %s: %s' % (paths, result))
            return {'code': -1, 'msg': 'failed to pause with %s: %s' % (paths, result['msg'])}
        except BaseException as e:
            logging.error('failed to pause: %s' % e)
            return {'code': -1, 'msg': 'failed to pause: %s' % e}

    async def hls_status(self, request):
        try:
            params = query_string(request)
            fullpath = params['fullpath']
            result = await self._utils.hls_status(fullpath)
            if result['status']:
                return {'code': 0, 'msg': result['msg']}
            logging.error('failed to get hls status of %s: %s' %
                          (fullpath, result))
            return {'code': -1, 'msg': 'failed to get hls status of %s: %s' % (fullpath, result['msg'])}
        except BaseException as e:
            logging.error('failed to get hls status: %s' % e)
            return {'code': -1, 'msg': 'failed to get hls status: %s' % e}

    async def update_poster(self, request):
        try:
            params = await request.json()
            paths = json.loads(params.get('paths', '[]'), encoding='utf-8')
            result = await self._utils.update_poster(paths)
            if result['status']:
                return {'code': 0, 'msg': result['msg']}
            logging.error('failed to update poster with %s: %s' %
                          (paths, result))
            return {'code': -1, 'msg': 'failed to update poster with %s: %s' % (paths, result['msg'])}
        except BaseException as e:
            logging.error('failed to update poster: %s' % e)
            return {'code': -1, 'msg': 'failed to update poster: %s' % e}
